/*
 * @Author: 生俊甫 1758142861@qq.com
 * @Date: 2024-06-06 17:58:27
 * @LastEditors: 生俊甫 1758142861@qq.com
 * @LastEditTime: 2024-06-16 14:18:27
 * @FilePath: /sjf/2024-project/2024_centos/source/util.hpp
 * @Description: 该文件主要实现的是五子棋下的一些API的封装,供在后面调用修改
 */
#pragma once

#include <iostream>
#include <memory>
#include <sstream>
#include <fstream>
#include <mysql/mysql.h>
#include <jsoncpp/json/json.h>
#include "../log/logger.hpp"

class util_mysql
{
public:
    //mysql句柄的初始化操作
    static MYSQL* mysql_create(const std::string &host,
                               const std::string &username,
                               const std::string &password,
                               const std::string dbname,
                               const unsigned int port = 3306)
    {
        //创建句柄
        MYSQL* mysql = mysql_init(nullptr);
        if(mysql == nullptr)
        {
            ERR_LOG("mysql init err!");
            return nullptr;
        }
        //连接数据库服务
        if(mysql_real_connect(mysql,host.c_str(),username.c_str(),
                        password.c_str(),dbname.c_str(),port,nullptr,0) == nullptr)
        {
            ERR_LOG("mysql connect err: %s",mysql_error(mysql));
            return nullptr;
        }
        //修改字符集
        if(mysql_set_character_set(mysql,"utf8") != 0)
        {
            ERR_LOG("mysql character set err: %s",mysql_error(mysql));
            return nullptr;
        }
        return mysql;
    }
    //执行sql语句,后序sql就是定义的CURD语句
    static bool mysql_exec(MYSQL* mysql,const std::string sql)
    {
        //执行函数
        if(mysql_query(mysql,sql.c_str()) != 0)
        {
            ERR_LOG("sql: %s err: %s",sql.c_str(),mysql_error(mysql));
            return false;
        }
        return true;
    }
    //关闭mysql服务
    static void mysql_destory(MYSQL* mysql)
    {
        if(mysql == nullptr)
            return ;
        mysql_close(mysql);
        mysql = nullptr;
        return ;
    }
};

class util_json
{
public:
    // 序列化: Json对象 -> 字符串
    // 输⼊输出型参数
    // root输⼊参数：表⽰要序列化的json对象
    // str输出参数: 表⽰序列化之后的字符串
    static bool serialize(const Json::Value& root,std::string& str)
    {
        //创建StreamWriterBuilder对象
        Json::StreamWriterBuilder swb;
        //使用unique_ptr智能指针管理StreamWriter对象(由StreamWriterBuilder实例化出)
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        //创建流来存放最后序列化出的结果
        std::stringstream ss;
        int ret = sw->write(root,&ss);
        if(ret != 0)
        {
            ERR_LOG("json serialize err!");
            return false;
        }
        str = ss.str();
        //此时不需要手动delete sw 因为交给了智能指针管理
        return true;
    }
    // 反序列化: 字符串 ->Json对象
    // 输⼊输出型参数
    // str输⼊参数: 表⽰需要反序列化的字符串
    // root输出参数：表⽰反序列化后的json对象
    static bool unserialize(const std::string& str, Json::Value& root)
    {
        //初始化一个CharReaderBuilder对象
        Json::CharReaderBuilder crb;
        //使用unique_ptr智能指针管理CharReader对象(由CharReaderBuilder实例化出)
        std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
        std::string errs;
        bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &root, &errs);
        if(ret == false)
        {
            ERR_LOG("json unserialize err: %s",errs.c_str());
            return false;
        }
        return true;
    }
};

//字符串分割
class util_split
{
public:
/**
     * 字符串分割函数参数介绍
     * src:表示要进行分割的字符串
     * sep:表示要以哪个基准为参照
     * res:表示将按照sep分割的子串放到res中
    */
    static int split(const std::string& src,const std::string& sep,std::vector<std::string>& res)
    {
        res.clear();
        size_t pos,idx = 0;
        //开始查找
        while(idx < src.size())
        {
            pos = src.find(sep,idx);
            //没有找打分隔符,那么直接插入
            if(pos == std::string::npos)
            {
                res.push_back(src.substr(idx));
                break;
            }
            //如果还是符号位
            if(pos == idx)
            {
                idx += sep.size();
                continue;
            }
            res.push_back(src.substr(idx,pos - idx));
            idx = pos + sep.size();
        }
        return res.size();
    }
};

//读取静态html文件数据
class util_file_read
{
public:
    /**
     * read_file()函数介绍
     * filename:要读取的文件名
     * body:表示将文件中的内容存放到body
    */
    static bool read_file(const std::string& filename, std::string& body)
    {
        std::ifstream file;
        //打开文件
        //binary 使用二进制方式打开文件
        file.open(filename.c_str(),std::ios::binary | std::ios::in);
        if(!file)
        {
            ERR_LOG("%s Open file failed!",filename.c_str());
            return false;
        }
        //计算文件大小
        file.seekg(0,std::ios::end);//跳转到文件末尾
        body.resize(file.tellg());
        file.seekg(0,std::ios::beg);
        //把读取的文件放入body
        file.read(&body[0],body.size());
        if(file.good() == false)
        {
            ERR_LOG("%s read failed!",filename.c_str());
            file.close();
            return false;
        }
        file.close();
        return true;
    }
};